/* 
 * Copyright 2014 Josef Hertl.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package caetus.pkcs11.tokenCapabilities;

import caetus.pkcs11.key.CipherEnum;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Map;

/**
 *
 * @author Josef Hertl
 */
public class TokenCapabilities {

    private Map<TokenCapability, TokenCapabilityValue> capabilityMap = new EnumMap<TokenCapability, TokenCapabilityValue>(TokenCapability.class);
    private CipherEnum workingSymmetricCipher;

    public TokenCapabilities() {
    }

    /**
     * Adds the given capability to the list of capabilities. Does NOT check if
     * the capability had been set before and simply overwrites any previous
     * settings.
     *
     * @param capability The type of capability, i.e. CREATE_RSA
     * @param value The value of the capability - usually
     * implemented_works_accordingly
     */
    public void addCapability(TokenCapability capability, TokenCapabilityValue value) {
        capabilityMap.put(capability, value);
    }

    /**
     * @return Unmodifiable map of capabilities
     */
    public Map<TokenCapability, TokenCapabilityValue> getCapabilityMap() {
        return Collections.unmodifiableMap(capabilityMap);
    }

    /**
     * @param capability The queried capability (i.e. CREATE_RSA)
     * @return Value of the required capability. NEVER returns null - if the
     * capability is not mapped, it returns NOT_TESTED
     */
    public TokenCapabilityValue getCapabilityValue(TokenCapability capability) {
        if (capabilityMap.get(capability) == null) {
            return TokenCapabilityValue.NOT_TESTED;
        }
        return capabilityMap.get(capability);
    }

    /**
     * @param capability The requested capability.
     * @return True if the capability is working either standardly or
     * non-standardly, false otherwise.
     */
    public boolean capabilityWorking(TokenCapability capability) {
        TokenCapabilityValue tokenCapabilityValue = capabilityMap.get(capability);
        if (tokenCapabilityValue != null) {
            return tokenCapabilityValue.equals(TokenCapabilityValue.WORKS_ACCORDINGLY) || capabilityMap.get(capability).equals(TokenCapabilityValue.WORKS_NON_STANDARDLY);
        } else {
            return false;
        }
    }

    /**
     * Determines whether at least one capability in the given group works.
     * Symmetric cryptography includes encryption, decryption, key creation and
     * key generation. Same for asymmetric cryptography. Changing attributes
     * only deals with the changing attributes itself.
     *
     * @param capabilityGroup The requested group.
     * @return True if at least one capability within the group is working,
     * false otherwise.
     */
    public boolean capabilityGroupWorking(TokenCapabilityGroup capabilityGroup) {
        for (TokenCapability capability : capabilityMap.keySet()) {
            if (capability.getCapabilityGroup().equals(capabilityGroup)) {
                if (capabilityWorking(capability)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Prints the list of capabilities to the standard output
     */
    public void printCapabilities() {
        System.out.println("Token capabilities:");
        for (TokenCapability capability : capabilityMap.keySet()) {
            System.out.println(capability + ": " + capabilityMap.get(capability));
        }
    }

    public CipherEnum getWorkingSymmetricCipher() {
        return workingSymmetricCipher;
    }

    public void setWorkingSymmetricCipher(CipherEnum workingSymmetricCipher) {
        this.workingSymmetricCipher = workingSymmetricCipher;
    }
}
